<?php
declare(strict_types=1);

namespace App\Middleware;

use App\Constants\ErrorCode;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use function Hyperf\Support\env;

/**
 * 签名验证中间件
 * Class CheckSignMiddleware
 * @package App\Middleware
 */
class CheckSignMiddleware implements MiddlewareInterface
{
    protected ContainerInterface $container;

    protected RequestInterface $request;

    protected HttpResponse $response;

    public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request)
    {
        $this->container = $container;
        $this->response = $response;
        $this->request = $request;
    }

    /**
     * Notes: 前置验证签名中间件
     * User: Ken
     * DateTime: 2022/03/09 16:45
     * @param ServerRequestInterface $request
     * @param RequestHandlerInterface $handler
     * @return ResponseInterface
     */
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if (isLocal()) {
            return $handler->handle($request);
        }

        $param = array_merge($post = $request->getParsedBody(), $get = $request->getQueryParams());
        if (empty($param) || empty($param['timestamp']) || empty($param['sign'])) {
            abort(ErrorCode::SIGNATURE_ERROR);
        }

        // sign不参与校验字符串拼接
        $param_sign = $param['sign'];
        unset($param['sign']);
        ksort($param);

        // urldecode 使带json值的参数不被自动编码，与客户端保持一致
        $queryString = urldecode(http_build_query($param));
        $sign = md5(env('SIGN_SECRET', 'Dream') . $queryString);
        if ($param_sign !== $sign) {
            abort(ErrorCode::SIGNATURE_ERROR);
        }

        //签名用的字段不用户进入逻辑
        unset($post['sign'], $get['sign']);

        return $handler->handle($request->withParsedBody($post)->withQueryParams($get));
    }
}
